package cn.gs.util.net;

// @author gs
import java.io.*;
import java.net.Socket;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Level;
import java.util.logging.Logger;

public class DefaultSocket implements SocketAgent {

    public static String remoteIP(Socket socket) {
        return socket.getRemoteSocketAddress().toString();
    }

    public String remoteIP() {
        return remoteIP(socket);
    }

    public static String localIP(Socket socket) {
        return socket.getLocalSocketAddress().toString();
    }

    public String localIP() {
        return localIP(socket);
    }
    final Object readLock = new Object(), writeLock = new Object();
    private Socket socket;
    DisconnectListener on;
    protected BufferedWriter bw;
    protected BufferedReader br;

    public void setDisconnectListener(DisconnectListener on) {
        this.on = on;
    }

    protected void onDisconnect(Throwable th) {
        Logger.getLogger(DefaultSocket.class.getName()).log(Level.INFO, "On_Disconnect_" + remoteIP(), th);
        try {
            socket.close();
        } catch (Throwable ex) {
            Logger.getLogger(DefaultSocket.class.getName()).log(Level.WARNING, "Disconnect_close_socket", ex);
        }
        if (on != null) {
            on.onDisconnect(th);
        }
    }

    @Override
    public void writeLine(String msg) throws IOException {
        write(msg + "\n");
    }

    @Override
    public void write(String msg) throws IOException {
        try {
            synchronized (writeLock) {
                Logger.getLogger(DefaultSocket.class.getName()).log(Level.FINEST, "{0}>{1}>{2}", new String[]{localIP(), msg, remoteIP()});
                bw.write(msg);
                bw.flush();
            }
        } catch (IOException ex) {
            Logger.getLogger(DefaultSocket.class.getName()).log(Level.WARNING, null, ex);
            onDisconnect(ex);
            try {
                bw.close();
            } catch (Throwable e) {
            }
            throw ex;
        }
    }

    @Override
    public String readLine() throws IOException {
        try {
            synchronized (readLock) {
                String s = br.readLine();
                Logger.getLogger(DefaultSocket.class.getName()).log(Level.FINEST, "{0}<{1}<{2}", new String[]{localIP(), s, remoteIP()});
                return s;
            }
        } catch (IOException ex) {
            Logger.getLogger(DefaultSocket.class.getName()).log(Level.WARNING, null, ex);
            onDisconnect(ex);
            try {
                br.close();
            } catch (Throwable e) {
            }
            throw ex;
        }
    }

    @Override
    public boolean supportReconnect() {
        return false;
    }

    public Socket getSocket() {
        return socket;
    }

    public void setSocket(Socket socket) throws IOException {
        synchronized (readLock) {
            synchronized (writeLock) {
                this.socket = socket;
                this.br = new BufferedReader(new InputStreamReader(getSocket().getInputStream()));
                this.bw = new BufferedWriter(new OutputStreamWriter(getSocket().getOutputStream()));
            }
        }
    }
}
